﻿using System;
using System.Collections.Generic;
using System.Linq;

using mvcForum.Core.Abstractions.Interfaces;
using mvcForum.Core.Interfaces.Data;

namespace mvcForum.Core.Configuration {

	public class MVCForumDBConfig : IConfiguration {
		private readonly IRepository<ForumSettings> settingsRepo;
		private readonly IContext context;

		private static class Keys {
			public const String TopicsPerPage = "TopicsPerPage";
			public const String MessagesPerPage = "MessagesPerPage";
			public const String DefaultCulture = "DefaultCulture";
			public const String DefaultTimezone = "DefaultTimezone";
			public const String SiteURL = "SiteURL";
			public const String RobotEmailAddress = "RobotEmailAddress";
			public const String RobotName = "RobotName";
			public const String AsynchronousAntiSpam = "AsynchronousAntiSpam";
			public const String MaxFileSize = "MaxFileSize";
			public const String MaxAttachmentsSize = "MaxAttachmentsSize";
			public const String AllowedExtensions = "AllowedExtensions";
			public const String ShowOldPostsOnReply = "ShowOldPostsOnReply";
			public const String PostsOnReply = "PostsOnReply";
			public const String AllowUserDefinedTheme = "AllowUserDefinedTheme";
			public const String Theme = "Theme";
			public const String SpamAverage = "SpamAverage";
			public const String NewUserGroups = "NewUserGroups";
			public const String CheckForNews = "CheckForNews";
			public const String Editor = "Editor";
			public const String ShowDeletedMessages = "ShowDeletedMessages";
			public const String ShowOnlineUsers = "ShowOnlineUsers";
			public const String UseForumAccountController = "UseForumAccountController";
			public const String AllowSignUp = "AllowSignUp";
			public const String AllowLocalUsers = "AllowLocalUsers";
			public const String AllowOpenAuthUsers = "AllowOpenAuthUsers";
			public const String RequireEmailValidation = "RequireEmailValidation";
			public const String ValidationSubject = "ValidationSubject";
			public const String ValidationBody = "ValidationBody";
			public const String ForgottenPasswordSubject = "ForgottenPasswordSubject";
			public const String ForgottenPasswordBody = "ForgottenPasswordBody";
			public const String RequireRulesAccept = "RequireRulesAccept";
			public const String SignUpRules = "SignUpRules";
			public const String InformOnQuarantine = "InformOnQuarantine";
			public const String RedirectUrlLoggedIn = "RedirectUrlLoggedIn";
			public const String RedirectUrlRegistrered = "RedirectUrlRegistrered";
			public const String RedirectUrlLoggedOut = "RedirectUrlLoggedOut";
			public const String AllowQuickReply = "AllowQuickReply";
			public const String AuthorName = "AuthorName";
		}

		public MVCForumDBConfig(IContext context) {
			this.context = context;
			this.settingsRepo = this.context.GetRepository<ForumSettings>();
			this.NewUserGroups = new List<Int32>();
			this.AllowedExtensions = new List<String>();
			IList<ForumSettings> sett = this.Settings;
		}

		private IList<ForumSettings> pvtSettings;
		private IList<ForumSettings> Settings {
			get {
				if (this.pvtSettings == null) {
					try {
						this.pvtSettings = settingsRepo.ReadAll().ToList();
						this.SetDefaults(this.pvtSettings);
					}
					catch {
					}
				}

				return pvtSettings;
			}
		}

		private void SetDefaults(IList<ForumSettings> settings) {
			var setting = settings.Where(x => x.Key == Keys.TopicsPerPage);
			this.TopicsPerPage = this.GetInt32(setting, Keys.TopicsPerPage, 30);
			setting = settings.Where(x => x.Key == Keys.MessagesPerPage);
			this.MessagesPerPage = this.GetInt32(setting, Keys.MessagesPerPage, 20);
			setting = settings.Where(x => x.Key == Keys.DefaultCulture);
			this.DefaultCulture = this.GetString(setting, Keys.DefaultCulture, "en-GB");
			setting = settings.Where(x => x.Key == Keys.DefaultTimezone);
			this.DefaultTimezone = this.GetString(setting, Keys.DefaultTimezone, "GMT Standard Time");
			setting = settings.Where(x => x.Key == Keys.SiteURL);
			this.SiteURL = this.GetString(setting, Keys.SiteURL, "http://localhost");
			setting = settings.Where(x => x.Key == Keys.RobotEmailAddress);
			this.RobotEmailAddress = this.GetString(setting, Keys.RobotEmailAddress, "robot@mvcforum.org");
			setting = settings.Where(x => x.Key == Keys.RobotName);
			this.RobotName = this.GetString(setting, Keys.RobotName, "mvcForum");
			setting = settings.Where(x => x.Key == Keys.AsynchronousAntiSpam);
			this.AsynchronousAntiSpam = this.GetBoolean(setting, Keys.AsynchronousAntiSpam, true);
			setting = settings.Where(x => x.Key == Keys.MaxFileSize);
			this.MaxFileSize = this.GetInt32(setting, Keys.MaxFileSize, 2000000);
			setting = settings.Where(x => x.Key == Keys.MaxAttachmentsSize);
			this.MaxAttachmentsSize = this.GetInt32(setting, Keys.MaxAttachmentsSize, 10000000);
			setting = settings.Where(x => x.Key == Keys.AllowedExtensions);
			this.AllowedExtensions = this.GetString(setting, Keys.AllowedExtensions, "jpg;png;gif").Split(new Char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
			setting = settings.Where(x => x.Key == Keys.ShowOldPostsOnReply);
			this.ShowOldPostsOnReply = this.GetBoolean(setting, Keys.ShowOldPostsOnReply, true);
			setting = settings.Where(x => x.Key == Keys.PostsOnReply);
			this.PostsOnReply = this.GetInt32(setting, Keys.PostsOnReply, 10);
			setting = settings.Where(x => x.Key == Keys.AllowUserDefinedTheme);
			this.AllowUserDefinedTheme = this.GetBoolean(setting, Keys.AllowUserDefinedTheme, true);
			setting = settings.Where(x => x.Key == Keys.Theme);
			this.Theme = this.GetString(setting, Keys.Theme, "");
			setting = settings.Where(x => x.Key == Keys.SpamAverage);
			this.SpamAverage = this.GetInt32(setting, Keys.SpamAverage, 100);
			setting = settings.Where(x => x.Key == Keys.NewUserGroups);
			this.NewUserGroups = this.GetInt32List(setting, Keys.NewUserGroups);
			setting = settings.Where(x => x.Key == Keys.CheckForNews);
			this.CheckForNews = this.GetBoolean(setting, Keys.CheckForNews, false);
			setting = settings.Where(x => x.Key == Keys.Editor);
			this.Editor = this.GetString(setting, Keys.Editor, "");
			setting = settings.Where(x => x.Key == Keys.ShowDeletedMessages);
			this.ShowDeletedMessages = this.GetBoolean(setting, Keys.ShowDeletedMessages, true);
			setting = settings.Where(x => x.Key == Keys.ShowOnlineUsers);
			this.ShowOnlineUsers = this.GetBoolean(setting, Keys.ShowOnlineUsers, false);
			setting = settings.Where(x => x.Key == Keys.UseForumAccountController);
			this.UseForumAccountController = this.GetBoolean(setting, Keys.UseForumAccountController, true);
			setting = settings.Where(x => x.Key == Keys.AllowLocalUsers);
			this.AllowLocalUsers = this.GetBoolean(setting, Keys.AllowLocalUsers, true);
			setting = settings.Where(x => x.Key == Keys.AllowSignUp);
			this.AllowSignUp = this.GetBoolean(setting, Keys.AllowSignUp, true);
			setting = settings.Where(x => x.Key == Keys.RequireEmailValidation);
			this.RequireEmailValidation = this.GetBoolean(setting, Keys.RequireEmailValidation, true);
			setting = settings.Where(x => x.Key == Keys.AllowOpenAuthUsers);
			this.AllowOpenAuthUsers = this.GetBoolean(setting, Keys.AllowOpenAuthUsers, false);
			setting = settings.Where(x => x.Key == Keys.ValidationSubject);
			this.ValidationSubject = this.GetString(setting, Keys.ValidationSubject, "New account on MVC Forum");
			setting = settings.Where(x => x.Key == Keys.ValidationBody);
			this.ValidationBody = this.GetString(setting, Keys.ValidationBody, "Welcome to your new account on MVC Forum, please follow the link to activate your account {Url}");
			setting = settings.Where(x => x.Key == Keys.RequireRulesAccept);
			this.RequireRulesAccept = this.GetBoolean(setting, Keys.RequireRulesAccept, false);
			setting = settings.Where(x => x.Key == Keys.SignUpRules);
			this.SignUpRules = this.GetString(setting, Keys.SignUpRules, "");
			setting = settings.Where(x => x.Key == Keys.InformOnQuarantine);
			this.InformOnQuarantine = this.GetBoolean(setting, Keys.InformOnQuarantine, true);
			setting = settings.Where(x => x.Key == Keys.ForgottenPasswordSubject);
			this.ForgottenPasswordSubject = this.GetString(setting, Keys.ForgottenPasswordSubject, "Your new password from MVC Forum");
			setting = settings.Where(x => x.Key == Keys.ForgottenPasswordBody);
			this.ForgottenPasswordBody = this.GetString(setting, Keys.ForgottenPasswordBody, "You have requested a new password for your account on MVC Forum. Your new password is: {Password}");
			setting = settings.Where(x => x.Key == Keys.RedirectUrlLoggedIn);
			this.RedirectUrlLoggedIn = this.GetString(setting, Keys.RedirectUrlLoggedIn, "/forum");
			setting = settings.Where(x => x.Key == Keys.RedirectUrlRegistrered);
			this.RedirectUrlRegistrered = this.GetString(setting, Keys.RedirectUrlRegistrered, "/forum/account/success");
			setting = settings.Where(x => x.Key == Keys.RedirectUrlLoggedOut);
			this.RedirectUrlLoggedOut = this.GetString(setting, Keys.RedirectUrlLoggedOut, "/forum");
			setting = settings.Where(x => x.Key == Keys.AllowQuickReply);
			this.AllowQuickReply = this.GetBoolean(setting, Keys.AllowQuickReply, true);
			setting = settings.Where(x => x.Key == Keys.AuthorName);
			this.AuthorName = this.GetInt32(setting, Keys.AuthorName, 0);

			this.context.SaveChanges();
		}

		private Int32 GetInt32(IEnumerable<ForumSettings> setting, String key, Int32 defaultValue) {
			ForumSettings set = null;
			if (setting == null || !setting.Any()) {
				set = new ForumSettings(key, defaultValue);
				this.settingsRepo.Create(set);
			}
			else {
				set = setting.First();
			}
			if (!set.GetInt32().HasValue) {
				set.SetInt32(defaultValue);
			}
			return set.GetInt32().Value;
		}

		private String GetString(IEnumerable<ForumSettings> setting, String key, String defaultValue) {
			ForumSettings set = null;
			if (setting == null || !setting.Any()) {
				set = new ForumSettings(key, defaultValue);
				this.settingsRepo.Create(set);
			}
			else {
				set = setting.First();
			}
			return set.Value;
		}

		private IList<Int32> GetInt32List(IEnumerable<ForumSettings> setting, String key) {
			ForumSettings set = null;
			if (setting == null || !setting.Any()) {
				set = new ForumSettings(key, "");
				this.settingsRepo.Create(set);
			}
			else {
				set = setting.First();
			}
			return set.GetInt32List();
		}

		private Boolean GetBoolean(IEnumerable<ForumSettings> setting, String key, Boolean defaultValue) {
			ForumSettings set = null;
			if (setting == null || !setting.Any()) {
				set = new ForumSettings(key, defaultValue);
				this.settingsRepo.Create(set);
			}
			else {
				set = setting.First();
			}
			return set.GetBoolean();
		}

		private void SetString(String key, String value) {
			IEnumerable<ForumSettings> setting = this.Settings.Where(x => x.Key == key);
			ForumSettings set = null;
			if (!setting.Any()) {
				set = new ForumSettings(key, value);
				this.settingsRepo.Create(set);
			}
			else {
				set = setting.First();
				set.Value = value;
			}
		}

		private void SetInt32(String key, Int32 value) {
			IEnumerable<ForumSettings> setting = this.Settings.Where(x => x.Key == key);
			ForumSettings set = null;
			if (!setting.Any()) {
				set = new ForumSettings(key, value);
				this.settingsRepo.Create(set);
			}
			else {
				set = setting.First();
				set.SetInt32(value);
			}
		}

		private void SetInt32List(String key, IList<Int32> values) {
			IEnumerable<ForumSettings> setting = this.Settings.Where(x => x.Key == key);
			ForumSettings set = null;
			if (!setting.Any()) {
				set = new ForumSettings(key, "");
				this.settingsRepo.Create(set);
			}
			else {
				set = setting.First();
			}
			set.SetInt32List(values);
		}

		private void SetBoolean(String key, Boolean value) {
			IEnumerable<ForumSettings> setting = this.Settings.Where(x => x.Key == key);
			ForumSettings set = null;
			if (!setting.Any()) {
				set = new ForumSettings(key, value);
				this.settingsRepo.Create(set);
			}
			else {
				set = setting.First();
				set.SetBoolean(value);
			}
		}

		public void Save() {
			//using (IUnitOfWork uow = this.context.CreateUnitOfWork()) {

			this.SetInt32(Keys.TopicsPerPage, this.TopicsPerPage);
			this.SetInt32(Keys.MessagesPerPage, this.MessagesPerPage);
			this.SetString(Keys.DefaultCulture, this.DefaultCulture);
			this.SetString(Keys.DefaultTimezone, this.DefaultTimezone);
			this.SetString(Keys.SiteURL, this.SiteURL);
			this.SetString(Keys.RobotEmailAddress, this.RobotEmailAddress);
			this.SetString(Keys.RobotName, this.RobotName);
			this.SetBoolean(Keys.AsynchronousAntiSpam, this.AsynchronousAntiSpam);
			this.SetInt32(Keys.MaxFileSize, this.MaxFileSize);
			this.SetInt32(Keys.MaxAttachmentsSize, this.MaxAttachmentsSize);
			this.SetString(Keys.AllowedExtensions, String.Join(";", this.AllowedExtensions));
			this.SetBoolean(Keys.ShowOldPostsOnReply, this.ShowOldPostsOnReply);
			this.SetInt32(Keys.PostsOnReply, this.PostsOnReply);
			this.SetBoolean(Keys.AllowUserDefinedTheme, this.AllowUserDefinedTheme);
			this.SetString(Keys.Theme, this.Theme);
			this.SetInt32(Keys.SpamAverage, this.SpamAverage);
			this.SetInt32List(Keys.NewUserGroups, this.NewUserGroups);
			this.SetBoolean(Keys.CheckForNews, this.CheckForNews);
			this.SetString(Keys.Editor, this.Editor);
			this.SetBoolean(Keys.ShowDeletedMessages, this.ShowDeletedMessages);
			this.SetBoolean(Keys.ShowOnlineUsers, this.ShowOnlineUsers);
			this.SetBoolean(Keys.UseForumAccountController, this.UseForumAccountController);
			this.SetBoolean(Keys.AllowLocalUsers, this.AllowLocalUsers);
			this.SetBoolean(Keys.AllowSignUp, this.AllowSignUp);
			this.SetBoolean(Keys.RequireEmailValidation, this.RequireEmailValidation);
			this.SetBoolean(Keys.AllowOpenAuthUsers, this.AllowOpenAuthUsers);
			this.SetString(Keys.ValidationSubject, this.ValidationSubject);
			this.SetString(Keys.ValidationBody, this.ValidationBody);
			this.SetBoolean(Keys.RequireRulesAccept, this.RequireRulesAccept);
			this.SetString(Keys.SignUpRules, this.SignUpRules);
			this.SetBoolean(Keys.InformOnQuarantine, this.InformOnQuarantine);

			this.SetBoolean(Keys.AllowQuickReply, this.AllowQuickReply);
			this.SetInt32(Keys.AuthorName, this.AuthorName);

			this.SetString(Keys.RedirectUrlLoggedIn, this.RedirectUrlLoggedIn);
			this.SetString(Keys.RedirectUrlRegistrered, this.RedirectUrlRegistrered);
			this.SetString(Keys.RedirectUrlLoggedOut, this.RedirectUrlLoggedOut);

			this.context.SaveChanges();
			//}
		}

		#region Properties
		public Int32 TopicsPerPage { get; set; }
		public Int32 MessagesPerPage { get; set; }
		public String DefaultCulture { get; set; }
		public String DefaultTimezone { get; set; }
		public String SiteURL { get; set; }
		public String RobotEmailAddress { get; set; }
		public String RobotName { get; set; }
		public Boolean AsynchronousAntiSpam { get; set; }
		public Int32 MaxFileSize { get; set; }
		public Int32 MaxAttachmentsSize { get; set; }
		public IList<String> AllowedExtensions { get; set; }
		public IList<Int32> NewUserGroups { get; set; }
		public Boolean ShowDeletedMessages { get; set; }

		public Boolean ShowOldPostsOnReply { get; set; }
		public Int32 PostsOnReply { get; set; }

		public Boolean AllowUserDefinedTheme { get; set; }
		public String Theme { get; set; }
		public Boolean Editable { get { return true; } }

		public Int32 SpamAverage { get; set; }
		public Boolean CheckForNews { get; set; }

		public String Editor { get; set; }

		public Boolean ShowOnlineUsers { get; set; }

		public Boolean UseForumAccountController { get; set; }

		public Boolean AllowSignUp { get; set; }
		public Boolean AllowLocalUsers { get; set; }
		public Boolean RequireEmailValidation { get; set; }

		public String ValidationSubject { get; set; }
		public String ValidationBody { get; set; }

		public String ForgottenPasswordSubject { get; set; }
		public String ForgottenPasswordBody { get; set; }

		public Boolean AllowOpenAuthUsers { get; set; }

		public Boolean RequireRulesAccept { get; set; }
		public String SignUpRules { get; set; }

		public Boolean InformOnQuarantine { get; set; }

		public Boolean AllowQuickReply { get; set; }

		public Int32 AuthorName { get; set; }
		public AdminAuthorNameSetting AuthorNameSetting {
			get {
				return (AdminAuthorNameSetting)this.AuthorName;
			}
			set {
				this.AuthorName = (Int32)value;
			}
		}

		public String RedirectUrlLoggedIn { get; set; }
		public String RedirectUrlRegistrered { get; set; }
		public String RedirectUrlLoggedOut { get; set; }
		#endregion
	}
}